
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>Python: module gummworld2.gameclock</title>
</head><body bgcolor="#f0f0f8">

<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="gummworld2.html"><font color="#ffffff">gummworld2</font></a>.gameclock</strong></big></big> (version $Id: gameclock.py 407 2013-08-12 15:11:30Z stabbingfinger@gmail.com $)</font></td
><td align=right valign=bottom
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:///C:/cygwin/home/bw/devel/python/svn/gummworld2_devel/gamelib/gummworld2/gameclock.py">c:\cygwin\home\bw\devel\python\svn\gummworld2_devel\gamelib\gummworld2\gameclock.py</a></font></td></tr></table>
    <p><tt>gameclock.py&nbsp;-&nbsp;Game&nbsp;clock&nbsp;for&nbsp;Gummworld2.<br>
&nbsp;<br>
<a href="#GameClock">GameClock</a>&nbsp;is&nbsp;a&nbsp;fixed&nbsp;time-step&nbsp;clock&nbsp;that&nbsp;keeps&nbsp;time&nbsp;in&nbsp;terms&nbsp;of&nbsp;game<br>
time.&nbsp;It&nbsp;will&nbsp;attempt&nbsp;to&nbsp;keep&nbsp;game&nbsp;time&nbsp;close&nbsp;to&nbsp;real&nbsp;time,&nbsp;so&nbsp;if&nbsp;an<br>
interval&nbsp;takes&nbsp;one&nbsp;second&nbsp;of&nbsp;game&nbsp;time&nbsp;then&nbsp;the&nbsp;user&nbsp;experiences&nbsp;one<br>
second&nbsp;of&nbsp;real&nbsp;time.&nbsp;In&nbsp;the&nbsp;worst&nbsp;case&nbsp;where&nbsp;the&nbsp;CPU&nbsp;cannot&nbsp;keep&nbsp;up&nbsp;with<br>
the&nbsp;game&nbsp;load,&nbsp;game&nbsp;time&nbsp;will&nbsp;subjectively&nbsp;take&nbsp;longer&nbsp;but&nbsp;still&nbsp;remain<br>
accurate&nbsp;enough&nbsp;to&nbsp;keep&nbsp;game&nbsp;elements&nbsp;in&nbsp;synchronization.<br>
&nbsp;<br>
<a href="#GameClock">GameClock</a>&nbsp;manages&nbsp;time&nbsp;in&nbsp;the&nbsp;following&nbsp;ways:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;1.&nbsp;&nbsp;Register&nbsp;special&nbsp;callback&nbsp;functions&nbsp;that&nbsp;will&nbsp;be&nbsp;run&nbsp;when&nbsp;they<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;are&nbsp;due.<br>
&nbsp;&nbsp;&nbsp;&nbsp;2.&nbsp;&nbsp;Schedule&nbsp;game&nbsp;logic&nbsp;updates&nbsp;at&nbsp;a&nbsp;constant&nbsp;speed,&nbsp;independent&nbsp;of<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;frame&nbsp;rate.<br>
&nbsp;&nbsp;&nbsp;&nbsp;3.&nbsp;&nbsp;Schedule&nbsp;frames&nbsp;at&nbsp;capped&nbsp;frames-per-second,&nbsp;or&nbsp;uncapped.<br>
&nbsp;&nbsp;&nbsp;&nbsp;4.&nbsp;&nbsp;Invoke&nbsp;a&nbsp;pre-emptive&nbsp;pause&nbsp;callback&nbsp;when&nbsp;paused.<br>
&nbsp;&nbsp;&nbsp;&nbsp;5.&nbsp;&nbsp;Schedule&nbsp;miscellaneous&nbsp;items&nbsp;at&nbsp;user-configurable&nbsp;intervals.<br>
&nbsp;&nbsp;&nbsp;&nbsp;6.&nbsp;&nbsp;Optionally&nbsp;sleep&nbsp;between&nbsp;schedules&nbsp;to&nbsp;conserve&nbsp;CPU&nbsp;cycles.<br>
&nbsp;&nbsp;&nbsp;&nbsp;7.&nbsp;&nbsp;Gracefully&nbsp;handles&nbsp;corner&nbsp;cases.<br>
&nbsp;<br>
Note&nbsp;the&nbsp;Python&nbsp;Library&nbsp;docs&nbsp;mention&nbsp;that&nbsp;not&nbsp;all&nbsp;computer&nbsp;platforms'<br>
time&nbsp;functions&nbsp;return&nbsp;time&nbsp;fractions&nbsp;of&nbsp;a&nbsp;second.&nbsp;This&nbsp;module&nbsp;will&nbsp;not<br>
work&nbsp;on&nbsp;such&nbsp;platforms.<br>
&nbsp;<br>
USAGE<br>
&nbsp;<br>
Callback:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;clock&nbsp;=&nbsp;<a href="#GameClock">GameClock</a>(<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;update_callback=update_world,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;frame_callback=draw_scene,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pause_callback=pause_game)<br>
&nbsp;&nbsp;&nbsp;&nbsp;while&nbsp;1:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clock.tick()<br>
&nbsp;<br>
Special&nbsp;callbacks&nbsp;can&nbsp;be&nbsp;directly&nbsp;set&nbsp;and&nbsp;cleared&nbsp;at&nbsp;any&nbsp;time:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;clock.update_callback&nbsp;=&nbsp;my_new_update<br>
&nbsp;&nbsp;&nbsp;&nbsp;clock.frame_callback&nbsp;=&nbsp;my_new_draw<br>
&nbsp;&nbsp;&nbsp;&nbsp;clock.pause_callback&nbsp;=&nbsp;my_new_pause<br>
&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;clock.update_callback&nbsp;=&nbsp;None<br>
&nbsp;&nbsp;&nbsp;&nbsp;clock.frame_callback&nbsp;=&nbsp;None<br>
&nbsp;&nbsp;&nbsp;&nbsp;clock.pause_callback&nbsp;=&nbsp;None<br>
&nbsp;<br>
Scheduling&nbsp;miscellanous&nbsp;callbacks:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;every_second_of_every_day(dt):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"..."<br>
&nbsp;&nbsp;&nbsp;&nbsp;clock.schedule_interval(every_second_of_every_day,&nbsp;1.0)<br>
&nbsp;<br>
The&nbsp;update_callback&nbsp;receives&nbsp;a&nbsp;single&nbsp;DT&nbsp;argument,&nbsp;which&nbsp;is&nbsp;the&nbsp;time-step<br>
in&nbsp;seconds&nbsp;since&nbsp;the&nbsp;last&nbsp;update.<br>
&nbsp;<br>
The&nbsp;frame_callback&nbsp;receives&nbsp;a&nbsp;single&nbsp;INTERPOLATION&nbsp;argument,&nbsp;which&nbsp;is&nbsp;the<br>
fractional&nbsp;position&nbsp;in&nbsp;time&nbsp;of&nbsp;the&nbsp;frame&nbsp;within&nbsp;the&nbsp;current&nbsp;update&nbsp;time-<br>
step.&nbsp;It&nbsp;is&nbsp;a&nbsp;float&nbsp;in&nbsp;the&nbsp;range&nbsp;0.0&nbsp;to&nbsp;1.0.<br>
&nbsp;<br>
The&nbsp;pause_callback&nbsp;receives&nbsp;no&nbsp;arguments.<br>
&nbsp;<br>
User-defined&nbsp;interval&nbsp;callbacks&nbsp;accept&nbsp;at&nbsp;least&nbsp;a&nbsp;DT&nbsp;argument,&nbsp;which&nbsp;is<br>
the&nbsp;scheduled&nbsp;item's&nbsp;interval,&nbsp;and&nbsp;optional&nbsp;user-defined&nbsp;arguments.&nbsp;See<br>
<a href="#GameClock">GameClock</a>.schedule_interval.<br>
&nbsp;<br>
DEPRECATIONS<br>
&nbsp;<br>
Old&nbsp;Style&nbsp;Game&nbsp;Loop<br>
&nbsp;<br>
Use&nbsp;of&nbsp;the&nbsp;old&nbsp;style&nbsp;game&nbsp;loop&nbsp;is&nbsp;deprecated.&nbsp;Don't&nbsp;do&nbsp;this&nbsp;anymore:<br>
&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;clock.update_ready:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;update(clock.dt_update)<br>
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;clock.frame_ready:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;draw(clock.interpolate)<br>
&nbsp;<br>
The&nbsp;old&nbsp;style&nbsp;game&nbsp;loop&nbsp;will&nbsp;work&nbsp;on&nbsp;sufficiently&nbsp;fast&nbsp;hardware.&nbsp;Timekeeping<br>
will&nbsp;break&nbsp;on&nbsp;slow&nbsp;hardware&nbsp;that&nbsp;cannot&nbsp;keep&nbsp;up&nbsp;with&nbsp;a&nbsp;heavy&nbsp;workload.&nbsp;This&nbsp;is<br>
because&nbsp;the&nbsp;old&nbsp;style&nbsp;ignores&nbsp;the&nbsp;cost&nbsp;of&nbsp;the&nbsp;frame&nbsp;routine.&nbsp;By&nbsp;using&nbsp;callbacks<br>
instead,&nbsp;cost&nbsp;is&nbsp;factored&nbsp;into&nbsp;the&nbsp;frame&nbsp;scheduling&nbsp;and&nbsp;overloading&nbsp;the&nbsp;CPU&nbsp;has<br>
fewer&nbsp;negative&nbsp;side&nbsp;effects.<br>
&nbsp;<br>
The&nbsp;update_ready&nbsp;and&nbsp;frame_ready&nbsp;public&nbsp;attributes&nbsp;have&nbsp;been&nbsp;removed.<br>
&nbsp;<br>
CREDITS<br>
&nbsp;<br>
The&nbsp;inspiration&nbsp;for&nbsp;this&nbsp;module&nbsp;came&nbsp;from&nbsp;Koen&nbsp;Witters's&nbsp;superb&nbsp;article<br>
"deWiTTERS&nbsp;Game&nbsp;Loop",&nbsp;aka&nbsp;"Constant&nbsp;Game&nbsp;Speed&nbsp;independent&nbsp;of&nbsp;Variable&nbsp;FPS"<br>
at&nbsp;<a href="http://www.koonsolo.com/news/dewitters-gameloop/">http://www.koonsolo.com/news/dewitters-gameloop/</a>.<br>
&nbsp;<br>
The&nbsp;clock&nbsp;was&nbsp;changed&nbsp;to&nbsp;use&nbsp;a&nbsp;fixed&nbsp;time-step&nbsp;after&nbsp;many&nbsp;discussions&nbsp;with<br>
DR0ID,&nbsp;and&nbsp;a&nbsp;few&nbsp;readings&nbsp;of<br>
<a href="http://gafferongames.com/game-physics/fix-your-timestep/">http://gafferongames.com/game-physics/fix-your-timestep/</a>.<br>
&nbsp;<br>
Thanks&nbsp;to&nbsp;Koen&nbsp;Witters,&nbsp;DR0ID,&nbsp;and&nbsp;Glenn&nbsp;Fiedler&nbsp;for&nbsp;sharing.<br>
&nbsp;<br>
Pythonated&nbsp;by&nbsp;Gummbum.&nbsp;While&nbsp;the&nbsp;builtin&nbsp;demo&nbsp;requires&nbsp;pygame,&nbsp;the&nbsp;module<br>
does&nbsp;not.&nbsp;The&nbsp;<a href="#GameClock">GameClock</a>&nbsp;class&nbsp;is&nbsp;purely&nbsp;Python&nbsp;and&nbsp;should&nbsp;be&nbsp;compatible&nbsp;with<br>
other&nbsp;Python-based&nbsp;multi-media&nbsp;and&nbsp;game&nbsp;development&nbsp;libraries.</tt></p>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#aa55cc">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Modules</strong></big></font></td></tr>
    
<tr><td bgcolor="#aa55cc"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="time.html">time</a><br>
</td><td width="25%" valign=top></td><td width="25%" valign=top></td><td width="25%" valign=top></td></tr></table></td></tr></table><p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ee77aa">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Classes</strong></big></font></td></tr>
    
<tr><td bgcolor="#ee77aa"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><dl>
<dt><font face="helvetica, arial"><a href="__builtin__.html#object">__builtin__.object</a>
</font></dt><dd>
<dl>
<dt><font face="helvetica, arial"><a href="gummworld2.gameclock.html#GameClock">GameClock</a>
</font></dt></dl>
</dd>
</dl>
 <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="GameClock">class <strong>GameClock</strong></a>(<a href="__builtin__.html#object">__builtin__.object</a>)</font></td></tr>
    
<tr><td bgcolor="#ffc8d8"><tt>&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%">Methods defined here:<br>
<dl><dt><a name="GameClock-__init__"><strong>__init__</strong></a>(self, max_ups<font color="#909090">=30</font>, max_fps<font color="#909090">=0</font>, use_wait<font color="#909090">=False</font>, time_source<font color="#909090">=&lt;built-in function time&gt;</font>, update_callback<font color="#909090">=None</font>, frame_callback<font color="#909090">=None</font>, paused_callback<font color="#909090">=None</font>)</dt></dl>

<dl><dt><a name="GameClock-pause"><strong>pause</strong></a>(self)</dt><dd><tt>Pause&nbsp;the&nbsp;clock&nbsp;so&nbsp;that&nbsp;time&nbsp;does&nbsp;not&nbsp;elapse.<br>
&nbsp;<br>
While&nbsp;the&nbsp;clock&nbsp;is&nbsp;paused,&nbsp;no&nbsp;schedules&nbsp;will&nbsp;fire&nbsp;and&nbsp;<a href="#GameClock-tick">tick</a>()&nbsp;returns<br>
immediately&nbsp;without&nbsp;progressing&nbsp;internal&nbsp;counters.&nbsp;Game&nbsp;loops&nbsp;that<br>
completely&nbsp;rely&nbsp;on&nbsp;the&nbsp;clock&nbsp;will&nbsp;need&nbsp;to&nbsp;take&nbsp;over&nbsp;timekeeping&nbsp;and<br>
handling&nbsp;events;&nbsp;otherwise,&nbsp;the&nbsp;game&nbsp;will&nbsp;appear&nbsp;to&nbsp;deadlock.&nbsp;There&nbsp;are<br>
many&nbsp;ways&nbsp;to&nbsp;solve&nbsp;this&nbsp;scenario.&nbsp;For&nbsp;instance,&nbsp;another&nbsp;clock&nbsp;can&nbsp;be<br>
created&nbsp;and&nbsp;used&nbsp;temporarily,&nbsp;and&nbsp;the&nbsp;original&nbsp;swapped&nbsp;back&nbsp;in&nbsp;and<br>
resumed&nbsp;when&nbsp;needed.</tt></dd></dl>

<dl><dt><a name="GameClock-resume"><strong>resume</strong></a>(self)</dt><dd><tt>Resume&nbsp;the&nbsp;clock&nbsp;from&nbsp;the&nbsp;point&nbsp;that&nbsp;it&nbsp;was&nbsp;paused.</tt></dd></dl>

<dl><dt><a name="GameClock-schedule_interval"><strong>schedule_interval</strong></a>(self, func, interval, life<font color="#909090">=0</font>, args<font color="#909090">=[]</font>)</dt><dd><tt>Schedule&nbsp;an&nbsp;item&nbsp;to&nbsp;be&nbsp;called&nbsp;back&nbsp;each&nbsp;time&nbsp;an&nbsp;interval&nbsp;elapses.<br>
&nbsp;<br>
While&nbsp;the&nbsp;clock&nbsp;is&nbsp;paused&nbsp;time&nbsp;does&nbsp;not&nbsp;pass.<br>
&nbsp;<br>
Parameters:<br>
&nbsp;&nbsp;&nbsp;&nbsp;func&nbsp;-&gt;&nbsp;The&nbsp;callback&nbsp;function.<br>
&nbsp;&nbsp;&nbsp;&nbsp;interval&nbsp;-&gt;&nbsp;The&nbsp;time&nbsp;in&nbsp;seconds&nbsp;(float)&nbsp;between&nbsp;calls.<br>
&nbsp;&nbsp;&nbsp;&nbsp;life&nbsp;-&gt;&nbsp;The&nbsp;number&nbsp;of&nbsp;times&nbsp;the&nbsp;callback&nbsp;will&nbsp;fire,&nbsp;after&nbsp;which&nbsp;the<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;schedule&nbsp;will&nbsp;be&nbsp;removed.&nbsp;If&nbsp;the&nbsp;value&nbsp;0&nbsp;is&nbsp;specified,&nbsp;the&nbsp;event<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;will&nbsp;persist&nbsp;until&nbsp;manually&nbsp;unscheduled.<br>
&nbsp;&nbsp;&nbsp;&nbsp;args&nbsp;-&gt;&nbsp;A&nbsp;list&nbsp;that&nbsp;will&nbsp;be&nbsp;passed&nbsp;to&nbsp;the&nbsp;callback&nbsp;as&nbsp;an&nbsp;unpacked<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sequence,&nbsp;like&nbsp;so:&nbsp;item.func(*[item.interval]+item.args).</tt></dd></dl>

<dl><dt><a name="GameClock-tick"><strong>tick</strong></a>(self)</dt></dl>

<dl><dt><a name="GameClock-unschedule"><strong>unschedule</strong></a>(self, func)</dt><dd><tt>Unschedule&nbsp;a&nbsp;managed&nbsp;function.</tt></dd></dl>

<dl><dt><a name="GameClock-unschedule_by_id"><strong>unschedule_by_id</strong></a>(self, id)</dt><dd><tt>Unschedule&nbsp;a&nbsp;managed&nbsp;function.</tt></dd></dl>

<hr>
Data descriptors defined here:<br>
<dl><dt><strong>__dict__</strong></dt>
<dd><tt>dictionary&nbsp;for&nbsp;instance&nbsp;variables&nbsp;(if&nbsp;defined)</tt></dd>
</dl>
<dl><dt><strong>__weakref__</strong></dt>
<dd><tt>list&nbsp;of&nbsp;weak&nbsp;references&nbsp;to&nbsp;the&nbsp;object&nbsp;(if&nbsp;defined)</tt></dd>
</dl>
<dl><dt><strong>game_time</strong></dt>
<dd><tt>Virtual&nbsp;elapsed&nbsp;time&nbsp;in&nbsp;game&nbsp;milliseconds.</tt></dd>
</dl>
<dl><dt><strong>interpolate</strong></dt>
</dl>
<dl><dt><strong>max_fps</strong></dt>
</dl>
<dl><dt><strong>max_ups</strong></dt>
</dl>
<dl><dt><strong>paused</strong></dt>
<dd><tt>The&nbsp;real&nbsp;time&nbsp;at&nbsp;which&nbsp;the&nbsp;clock&nbsp;was&nbsp;paused,&nbsp;or&nbsp;zero&nbsp;if&nbsp;the&nbsp;clock<br>
is&nbsp;not&nbsp;paused.</tt></dd>
</dl>
</td></tr></table></td></tr></table><p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#55aa55">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr>
    
<tr><td bgcolor="#55aa55"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><strong>__author__</strong> = 'Gummbum, (c) 2011-2013'<br>
<strong>__version__</strong> = '$Id: gameclock.py 407 2013-08-12 15:11:30Z stabbingfinger@gmail.com $'</td></tr></table><p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#7799ee">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Author</strong></big></font></td></tr>
    
<tr><td bgcolor="#7799ee"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%">Gummbum,&nbsp;(c)&nbsp;2011-2013</td></tr></table>
</body></html>